Матч 46, Путь короля (KingsTour)

 

Имеется шахматная доска 8*8, колонки которой пронумерованы буквами от ‘a’ до ‘h’, а строки цифрами от 1 до 8. Одной из шахматных фигур является пешка. Пешка бьет по диагонали. Например, находясь на с3, она угрожает полям b4 и d4.

Строки king, pawnA и pawnB описывают положение короля и двух пешек А и В на доске в формате “<буква><цифра>”. Необходимо найти наименьшее число ходов короля, за которое он сможет сбить пешку А. Король не может становиться под удар пешек и выходить за границы шахматного поля. При необходимости король может сбить пешку В. Пешки не двигаются.

 

Класс: KingsTour

Метод: int attackPawns(string king, string pawnA, string pawnB)

Ограничения: каждая строка king, pawnA и pawnB имеет формат <буква><цифра>, ‘a’ £ <буква> £ ‘h’, 1 £ <цифра> £ 8, начальные позиции короля и пешек различны, король не находится под ударом ни одной из пешек.

 

Вход. Строки king, pawnA и pawnB, задающие начальные позиции короля и двух пешек.

 

Выход. Наименьшее количество ходов короля, за которое он сможет сбить пешку А.

 

Пример входа

king

pawnA

pawnB

“c4”

“e6”

“d5”

“g2”

“a8”

“a2”

“a3”

“b1”

“c1”

 

Пример выхода

2

6

7

 

 

РЕШЕНИЕ

графы, поиск в ширину

 

Рассмотрим два варианта движения короля:

1. Король направляется к пешке А несмотря на положение пешки В и съедает ее;

2. Король направляется к пешке В, съедает ее и потом двигается к пешке А.

В обоих случаях при движении короля используется кратчайший путь, который находится поиском в ширину. Находим наименьшее количество ходов в первом и во втором случаях и возвращаем наименьшее среди них значение.

В поля, находящиеся под ударом пешек, изначально поставим значения 1000. Таким образом при поиске в ширину король на них не зайдет. Начальные положения короля и двух пешек занесем соответственно в переменные (kx, ky), (pax, pay), (pbx, pby). Запустим bfs(kx, ky). Занесем в переменные a и b наименьшее число ходов, которыми можно добраться до пешки А и В соответственно: a = m[pax][pay], b = m[pbx][pby]. Если пешка В сбивается, то следует запустить bfs(pbx, pby), найдя таким образом кратчайший путь от пешки В до А. Добавим к b значение m[pax][pay] после второго вызова bfs. Таким образом в a содержится длина кратчайшего пути короля до достижения цели без сбивания пешки В, а в b – со сбиванием. Возвращаем меньшее значение среди a и b.

 

ПРОГРАММА

 

#include <cstdio>

#include <string>

#include <memory>

#include <deque>

using namespace std;

 

int m[10][10];

deque<pair<int,int> > d;

int xx[8] = {1, 1, 1, -1, -1, -1, 0, 0};

int yy[8] = {-1, 0, 1, -1, 0, 1, 1, -1};

 

int cango(int x, int y)

{

  if ((x < 1) || (x > 8) || (y < 1) || (y > 8) || (m[x][y] >= 0)) return 0;

  return 1;

}

 

void bfs(int x, int y)

{

  pair<int,int> temp;

  int i;

  m[x][y] = 0;

  d.push_back(make_pair(x,y));

  while(!d.empty())

  {

    temp = d[0]; d.pop_front();

    for(i = 0; i < 8; i++)

     if (cango(temp.first + xx[i],temp.second + yy[i]))

     {

       m[temp.first + xx[i]][temp.second + yy[i]] =

         m[temp.first][temp.second] + 1;

       d.push_back(make_pair(temp.first + xx[i],temp.second + yy[i]));

     }

  }

}

 

class KingsTour

{

public:

  int attackPawns(string king, string pawnA, string pawnB)

  {

    int kx = king[0] - 'a' + 1, ky = king[1] - '1' + 1;

    int pax = pawnA[0] - 'a' + 1, pay = pawnA[1] - '1' + 1;

    int pbx = pawnB[0] - 'a' + 1, pby = pawnB[1] - '1' + 1;

    int a, b;

 

    memset(m,-1,sizeof(m));

    m[pax-1][pay+1] = m[pax+1][pay+1] = 1000;

    m[pbx-1][pby+1] = m[pbx+1][pby+1] = 1000;

    bfs(kx,ky);

 

    a = m[pax][pay]; b = m[pbx][pby];

    memset(m,-1,sizeof(m));

    m[pax-1][pay+1] = m[pax+1][pay+1] = 1000;

    bfs(pbx,pby); b += m[pax][pay];

    return (a < b) ? a : b;

  }

};